/**
 * @file STL_HttpParser.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-02-18
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#include "STL_HttpParser.h"
#include "STL_Text.h"
#include "STLOG.h"
#include <regex>
#include "STL_URL.h"

namespace STL
{
    void STL_HttpParser::parse()
    {
        int count = 0;  //解析次数计数
        int max = 1024; //一次解析最大次数
        do
        {
            if (count++ > max)
            {
                return;
            }
            if (m_status == Wait_Request_Line)
            {
                std::regex s_regRequsetLine("(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT) ([^ \\s]+) (HTTP/1.[0|1]{1})\r\n");
                std::smatch result;
                if (std::regex_search(m_data, result, s_regRequsetLine))
                { //匹配到请求行
                    m_request.reset(new STL_HttpRequest());
                    m_request->m_method = result.str(1);
                    m_request->m_uri = result.str(2);
                    m_request->m_version = result.str(3);
                    m_request->m_headers.clear();
                    m_request->m_body.clear();
                    parseUri();
                    m_body_lenght = 0;
                    m_data = result.suffix();
                    m_status = Wait_Request_Header;
                }
                else
                { //未匹配到请求行
                    //Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
                    if (m_data.size() > 2067)                         // 7(method) + 1(space) +  2048(uri) + 1(space) + 8(version) + 2(\r\n)
                    {                                                 //超出请求行最大长度
                        m_data = m_data.substr(m_data.size() - 2067); // 超过请求行最大常长度前的数据不要了
                    }
                    return; // 没有请求行，等下次数据
                }
            }
            if (m_status == Wait_Request_Header)
            {
                size_t pos = m_data.find("\r\n\r\n");
                if (pos == std::string::npos)
                { // 未发现头部的结束标记
                    if (m_data.size() > 10240)
                    { // 数据量超过预期的数据量
                        stlog_warn("headers > 10240");
                        m_status = Wait_Request_Line; //从新解析请求行(此处不处理异常数据，有请求行分析处理异常数据)
                        continue;
                    }
                    else
                    {
                        return; // 头部没有接收全，等待后续数据
                    }
                }
                else
                { // 发现头部的结束标记
                    // 截取头部数据
                    std::string headers = m_data.substr(0, pos);
                    // 剩余数据
                    m_data = m_data.substr(pos + 4);
                    // 处理了头部数据
                    auto headerLines = STL_Text::split(headers, "\r\n");
                    bool isParseError = false;
                    for (size_t i = 0; i < headerLines.size(); i++)
                    {
                        auto key_value = STL_Text::split(headerLines.at(i), ": ");
                        if (key_value.size() < 2)
                        {
                            stlog_warn("headers > key_value warn %s", headerLines.at(i).c_str());
                            isParseError = true;
                            break;
                        }
                        std::string key = key_value.at(0);
                        std::string value = key_value.at(1);
                        if (STL_Text::toLowerStr(key) == "content-length")
                        {
                            m_body_lenght = std::stoul(value);
                            if (m_body_lenght > 1024 * 1024 * 16)
                            {
                                stlog_warn("headers > m_body_lenght > 16M [%zu]", m_body_lenght);
                            }
                        }
                        m_request->m_headers[key] = value;
                    }
                    if (isParseError)
                    {
                        m_status = Wait_Request_Line;
                        continue;
                    }
                    if (m_body_lenght > 0)
                    {
                        m_status = Wait_Request_Body;
                    }
                    else
                    {
                        // stlog_debug("http info without body!!!!\n");
                        if (m_RequestCallback)
                        {
                            m_RequestCallback(m_socketId, m_request);
                        }
                        m_status = Wait_Request_Line;
                        continue;
                    }
                }
            }
            if (m_status == Wait_Request_Body)
            {
                if (m_data.size() >= m_body_lenght)
                { // body接收完成
                    m_request->m_body = m_data.substr(0, m_body_lenght);
                    m_data = m_data.substr(m_body_lenght);
                    // stlog_debug("http info with body!!!!");
                    if (m_RequestCallback)
                    {
                        m_RequestCallback(m_socketId, m_request);
                    }
                    m_status = Wait_Request_Line;
                    continue;
                }
                else
                {           // body 未接收完成
                    return; // 退出解析，等下次数据
                }
            }
        } while (1);
    }
    void STL_HttpParser::parseUri()
    {
        std::string url = m_request->m_uri;
        size_t pos = 0;
        std::string flag;

        size_t start_path = pos;
        size_t end_path = url.find_first_of(";?#", pos);
        if (end_path != std::string::npos)
        {
            m_request->m_path = url.substr(start_path, end_path - start_path);
            flag = url.substr(end_path, 1);
            pos = end_path + 1;
        }
        else
        {
            m_request->m_path = url.substr(start_path);
            return;
        }
        if (flag == ";")
        {
            size_t start_parameter = pos;
            size_t end_parameter = url.find_first_of("?#", pos);
            if (end_parameter != std::string::npos)
            {
                m_request->m_parameter = url.substr(start_parameter, end_parameter - start_parameter);
                flag = url.substr(end_parameter, 1);
                pos = end_parameter + 1;
            }
            else
            {
                m_request->m_parameter = url.substr(start_parameter);
                return;
            }
        }
        if (flag == "?")
        {
            size_t start_query = pos;
            size_t end_query = url.find_first_of("#", pos);
            if (end_query != std::string::npos)
            {
                m_request->m_query = url.substr(start_query, end_query - start_query);
                parseQuery();
                flag = url.substr(end_query, 1);
                pos = end_query + 1;
            }
            else
            {
                m_request->m_query = url.substr(start_query);
                parseQuery();
                return;
            }
        }
        m_request->m_fragment = url.substr(pos);
    }
    void STL_HttpParser::parseQuery()
    {
        if (m_request->m_query.empty())
            return;
        std::string query = m_request->m_query;
        auto values = STL_Text::split(query, "&");
        for (size_t i = 0; i < values.size(); i++)
        {
            if (values.at(i).empty())
                continue;
            auto key_value = STL_Text::split(values.at(i), "=");
            std::string key = key_value.at(0);
            std::string value = "";
            if (key_value.size() >= 2)
            {
                value = STL::STL_URL::UrlDecode(key_value.at(1));
            }
            m_request->m_query_map[key] = value;
        }
    }
} // namespace STL
